/*
 * LAGMonster 2, OSCthulhu version
 */
MindFlayer : ManticorePiece
{
	classvar <scoreIndex, <activeButtons, <keyNames, <>userStates, <>buttonStates, <>synths;
	var scoreText, currentPart;
	var interface;
	
	var osc;
	
	*new
	{
		^super.new.init;
	}
	
	*initClass
	{
		Manticore.registerPiece('MindFlayer');	// register with Manticore
	}
	
	init
	{
		Manticore.group = "MF";
		
		MindFlayerServerItems.init;
		
		osc = List.new;
		
		userStates = Dictionary.new;
		
		scoreIndex = 0;
		
		currentPart = 0;
		
		keyNames = [
		"1","2","3","4","5","6",
		"q","w","e","r","t","y",
		"a","s","d","f","g","h",
		"z","x","c","v","b","n"
		];
		
		scoreText = MindFlayerPartI.scoreText;
		
		activeButtons = MindFlayerPartI.buttonStates;
		
		buttonStates = Array.fill(keyNames.size, {0.0});
		
		synths = Array.fill(keyNames.size, { nil });

		this.setupOSClisteners;
		this.storeSynthDefs;
		
		OSCthulhu.changePorts(57120);
		OSCthulhu.login(Manticore.group);
		
		// make the score buttons work
		Manticore.onScoreNext({
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 0, (scoreIndex+1)%scoreText.size);
		});
		Manticore.onScorePrevious({
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 0, (scoreIndex-1)%scoreText.size);
		});
		
		// args: scoreIndex, volume
		OSCthulhu.addSyncObject(
			Manticore.group++"_Global",
			Manticore.group,
			"glbl",
			[
				0,		// scoreIndex
				1.0,		// volume
				0		// part
			]
		);
		
		OSCthulhu.addSyncObject(
			OSCthulhu.userName++"_States",
			Manticore.group,
			"s",
			Array.fill(24, {0.0})
		);
	}
	
	setupOSClisteners
	{
		
		// addSyncObject
		osc.add(OSCthulhu.onAddSyncObject(\addScore, {|msg|
			var oscAddr, objName, group, subGroup, args;
			
			# oscAddr, objName, group, subGroup = msg;
			args = msg.copyRange(4,msg.size-1);
			
			if(subGroup.asString == "glbl",{
				scoreIndex = args[0];
				currentPart = args[2];
				Manticore.updateScore(scoreText[scoreIndex]);
				interface.updateButtonStates;
			});
			
			if(subGroup.asString == "s",{							MindFlayer.userStates.put(objName.asString,MindFlayerUser.new);
				args.do{|val,i| MindFlayer.userStates.at(objName.asString).states[i] = val; };
			});
		})
		);
		
		// setSyncArg
		osc.add(OSCthulhu.onSetSyncArg(\updateScore, {|msg|
			var oscAddr, objName, argIndex, argValue, group, subGroup;
			
			# oscAddr, objName, argIndex, argValue, group, subGroup = msg;
			

			// handle events for each part
			switch(
				currentPart,
				0, {
					MindFlayerPartI.setSyncArg(this, oscAddr, objName, argIndex, argValue, group, subGroup);
				},
				1, {
					MindFlayerPartII.setSyncArg(this, oscAddr, objName, argIndex, argValue, group, subGroup);
				},
				2, {
					
				}
			);
			
			if(subGroup.asString == "glbl", {
				switch(
					argIndex,
					0, {
						
						if(argValue != scoreIndex,{
							//TarasqueServerItems.changeEffects(scoreEffects[argValue].asString);
							scoreIndex = argValue;
							Manticore.updateScore(scoreText[scoreIndex]);
							interface.updateButtonStates;
						});
						
					},
					2, {
						if(argValue != currentPart,{
							// handle part changes here
							MindFlayerServerItems.synthGroup.release;
							
							interface.buttonRoutine.do{|r|
								r.stop;
							};
							
							OSCthulhu.removeSyncObject(OSCthulhu.userName++"_States");
							
							OSCthulhu.addSyncObject(
								OSCthulhu.userName++"_States",
								Manticore.group,
								"s",
								Array.fill(24, {0.0})
							);
							
							buttonStates = Array.fill(keyNames.size, {0.0});
							
							24.do{|i|
								synths[i] = nil;
							};
							
							currentPart = argValue;	
							
							switch(
								currentPart,
								0, {
									scoreText = MindFlayerPartI.scoreText;
									activeButtons = MindFlayerPartI.buttonStates;
								},
								1, {
									scoreText = MindFlayerPartII.scoreText;
									activeButtons = MindFlayerPartII.buttonStates;
								},
								2, {
									/*
									scoreText = MindFlayerPartIII.scoreText;
									activeButtons = MindFlayerPartIII.buttonStates;
									*/
								}
							);
							
							this.updateButtonStates;
							
						});
						
					}
				)
			});
			
		})
		);
		
		// remove sync object
		osc.add(OSCthulhu.onRemoveSyncObject(\removeUserStates, {|msg|
			var oscAddr, objName, group, subGroup;
			
			#oscAddr, objName, group, subGroup = msg;
			
			if(subGroup.asString == "s", {
				userStates.removeAt(objName.asString);
			});
		})
		);
		
	}
	
	free
	{
		synths.collect({|s| s.release; });
		osc.collect({|def| def.free; });
		OSCthulhu.removeSyncObject(OSCthulhu.userName++"_States");
		OSCthulhu.cleanup(Manticore.group);
		MindFlayerServerItems.free;
	}
	
	storeSynthDefs
	{
		MindFlayerPartI.storeSynthDefs;
	}
	
	getInterface
	{|p|
		interface = MindFlayerInterface.new;
		
		^p.layout_(HLayout( interface.getView; ));
	}
	
	updateButtonStates
	{
		interface.updateButtonStates;
	}
}

MindFlayerServerItems
{
	classvar <>currentVolume;
	classvar <synthGroup;
	classvar <audioToEffectsBus;
	classvar <effectGroup;
	classvar <effectSynths;
	
	*init
	{
		currentVolume = 1;
		synthGroup = Group.new;
		effectGroup = Group.after(synthGroup);
		
		switch(
			Manticore.speakerConfiguration,
			\stereo, {
				audioToEffectsBus = Bus.audio(Server.default, 2);
				effectSynths = Array.fill(2,{nil});
			},
			\quad, {
				audioToEffectsBus = Bus.audio(Server.default, 4);
				effectSynths = Array.fill(4,{nil});
			},
			\cube, {
				audioToEffectsBus = Bus.audio(Server.default, 8);
				effectSynths = Array.fill(8,{nil});
			}
		);
		
		effectSynths.size.do{|i|
			/*
			effectSynths[i] = Synth(
				"HomunculousFX",
				[
					"in",(HomunculusServerItems.audioToEffectsBus.index+i),
					"out",i
					
				],
				effectGroup
			);
			*/
		};
	}
	
	*free
	{
		synthGroup.free;
		effectGroup.free;
		audioToEffectsBus.free;
	}
}

MindFlayerInterface
{
	var osc;
	var buttons, volSlider;
	var <buttonRoutine;
	
	*new
	{
		^super.new.init;
	}
	
	init
	{
		osc = List.new;
		
		this.setupOSClisteners;
	}
	
	getView
	{
		var scrollView, interface;
		
		buttonRoutine = Array.fill(24, {nil});
		
		scrollView = [ScrollView().background_(Color.black),stretch:6];
		
		scrollView[0].addFlowLayout;
		
		StaticText(scrollView[0], 260@40).string_("Keys").stringColor_(Color.white);
		
		buttons = Array.fill(24,{ Button(scrollView[0], 40@40).canFocus_(false); });
		
		buttons.do{|btn,i|
			buttons[i].action_({|b|
				switch(
					b.value,
					0, {
						buttonRoutine[i] = {
							{
								0.1.wait;
								
								OSCthulhu.setSyncArg(
									OSCthulhu.userName++"_States",
									i,
									(MindFlayer.userStates.at(OSCthulhu.userName++"_States").states[i] - 0.04).clip(0.0,1.0)
								);
								
								if(MindFlayer.userStates.at(OSCthulhu.userName++"_States").states[i] <= 0.0,{
									buttonRoutine[i].stop;
									
									OSCthulhu.setSyncArg(
										OSCthulhu.userName++"_States",
										i,
										0.0
									);
								});
							}.loop;
						}.fork;
						
					},
					1, {
						buttonRoutine[i].stop;
						OSCthulhu.setSyncArg(
							OSCthulhu.userName++"_States",
							i,
							(MindFlayer.userStates.at(OSCthulhu.userName++"_States").states[i] + 0.08).clip(0.0,1.0)
						);
					}
				);
			});
		};
		
		MindFlayer.keyNames.do{|name,i|
			buttons[i].states_( [ [ name, Color.black, Color.black ] ] );
		};
		
		this.updateButtonStates;
		
		StaticText(scrollView[0], 260@20).string_("Volume").stringColor_(Color.white);
		
		volSlider = Slider(scrollView[0], 260@20).canFocus_(false);
		volSlider.action_({|s|
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 1, s.value.asFloat);
		});
		
		Button(scrollView[0], 84@20)
		.canFocus_(false)
		.states_([
			[ "I", Color.white, Color.gray(0.35) ]
		])
		.action_({
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 0, 0);
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 2, 0);
		});
		
		Button(scrollView[0], 85@20)
		.canFocus_(false)
		.states_([
			[ "II", Color.white, Color.gray(0.35) ]
		])
		.action_({
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 0, 0);
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 2, 1);
		});
		
		Button(scrollView[0], 85@20)
		.canFocus_(false)
		.states_([
			[ "III", Color.white, Color.gray(0.35) ]
		])
		.action_({
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 0, 0);
			OSCthulhu.setSyncArg(Manticore.group++"_Global", 2, 2);
		});
		
		scrollView[0].keyDownAction = { arg view, char, modifiers, unicode, keycode;
			MindFlayer.keyNames.do{|item,i|
				if(char.asString == item, {
					buttons[i].valueAction_(1);
				});
			};
		};
		
		scrollView[0].keyUpAction = { arg view, char, modifiers, unicode, keycode;
			MindFlayer.keyNames.do{|item,i|
				if(char.asString == item, {
					buttons[i].valueAction_(0);
				});
			};
		};
		
		^scrollView[0];
	}
	
	setupOSClisteners
	{
		// addSyncObject
		osc.add(OSCthulhu.onAddSyncObject(\addGlobalEffectsValues, {|msg|
			var oscAddr, objName, group, subGroup, args;
			
			# oscAddr, objName, group, subGroup = msg;
			args = msg.copyRange(4,msg.size-1);
			
			if(subGroup.asString == "glbl", {
				
				{
					volSlider.value_( args[1] );
					MindFlayerServerItems.synthGroup.set("vol",args[1].asFloat);
					MindFlayerServerItems.currentVolume = args[1].asFloat;
				}.defer;
			});
		})
		);
		
		// setSyncArg
		osc.add(OSCthulhu.onSetSyncArg(\setGlobalEffectsValues, {|msg|
			var oscAddr, objName, argIndex, argValue, group, subGroup;
			
			# oscAddr, objName, argIndex, argValue, group, subGroup = msg;
			
//			msg.do{|item,i| (i.asString ++ ":" + item).postln };
			
			if(subGroup.asString == "glbl", {
				switch(
					argIndex,
					0, {
						
					},
					1, { 
						{volSlider.value_( argValue )}.defer;
						MindFlayerServerItems.synthGroup.set("amp",argValue.asFloat);
						MindFlayerServerItems.effectGroup.set("amp",argValue.asFloat);
						MindFlayerServerItems.currentVolume = argValue;
					},
					2, {
						
					}
				)
			});
		})
		);
	}
	
	free
	{
		osc.collect({|def| def.free; });
	}
	
	updateButtonStates
	{
		
		MindFlayer.keyNames.do{|name,i|
			
			switch(
				MindFlayer.activeButtons[MindFlayer.scoreIndex][i],
				0, {
					{
					buttons[i].states_( [
						[
							name,
							Color.grey(MindFlayer.activeButtons[MindFlayer.scoreIndex][i]),
							Color.black
						]
					]);
					}.defer;
					
				},
				1, {
					{
					buttons[i].states_( [
						[
							name,
							Color.grey(MindFlayer.activeButtons[MindFlayer.scoreIndex][i]),
							Color.red(MindFlayer.buttonStates[i])
						],
						[
							name,
							Color.grey(MindFlayer.activeButtons[MindFlayer.scoreIndex][i]),
							Color.red(MindFlayer.buttonStates[i])
						]
					]);
					}.defer;
				}
			);
			
		};
	}
}

MindFlayerUser
{
	var <>states;
	
	*new
	{
		^super.new.init;
	}
	
	init
	{
		states = Array.fill(24, {0.0});
	}
}

// LAGMonster v2
MindFlayerPartI
{
	*scoreText
	{
		^[
			"r (play in waves throughout)",
			"r, f",
			"r, f, d",
			"f, d",
			"d, e",
			"r, f, d, e",
			"d, e, 3",
			"d, e, 3, 4",
			"e, 3, 4",
			"4, 5",
			"4, 5, t",
			"d, e, 3",
			"3, 4, 5, t, g",
			"t, g, b",
			"g, b, v",
			"g, b, v, c",
			"v, c, x",
			"v, c, x, s",
			"g, b, v, c, x, s",
			"x, s, w",
			"x, w",
			"w, 2",
			"s, 2", 
			"2",
			"2, 6",
			"2, 6, y",
			"6, y, h",
			"y, h, n",
			"h, n",
			"n",
			"n, z",
			"n, z, a",
			"z, a",
			"z, a, q",
			"a, q, 1",
			"1, 3",
			"1, 3, 4, h",
			"1, 3, 4, h, s, a, q"
		];
	}
	
	*buttonStates
	{
		^[
			// LAGMonster
			[	// r
				0,0,0,0,0,0,
				0,0,0,1,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// r f
				0,0,0,0,0,0,
				0,0,0,1,0,0,
				0,0,0,1,0,0,
				0,0,0,0,0,0
			],[	// r f d
				0,0,0,0,0,0,
				0,0,0,1,0,0,
				0,0,1,1,0,0,
				0,0,0,0,0,0
			],[	// f d
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,1,1,0,0,
				0,0,0,0,0,0
			],[	// d e
				0,0,0,0,0,0,
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,0,0,0,0
			],[	// r f d e
				0,0,0,0,0,0,
				0,0,1,1,0,0,
				0,0,1,1,0,0,
				0,0,0,0,0,0
			],[	// d e 3
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,0,0,0,0
			],[	// d e 3 4
				0,0,1,1,0,0,
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,0,0,0,0
			],[	// e 3 4
				0,0,1,1,0,0,
				0,0,1,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 4 5
				0,0,0,1,1,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 4 5 t
				0,0,0,1,1,0,
				0,0,0,0,1,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// d e 3
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,1,0,0,0,
				0,0,0,0,0,0
			],[	// 3 4 5 t g
				0,0,1,1,1,0,
				0,0,0,0,1,0,
				0,0,0,0,1,0,
				0,0,0,0,0,0
			],[	// t g b
				0,0,0,0,0,0,
				0,0,0,0,1,0,
				0,0,0,0,1,0,
				0,0,0,0,1,0
			],[	// g b v
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,1,0,
				0,0,0,1,1,0
			],[	// g b v c
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,1,0,
				0,0,1,1,1,0
			],[	// v c x
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,1,1,1,0,0
			],[	// v c x s
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,1,0,0,0,0,
				0,1,1,1,0,0
			],[	// g b v c x s
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,1,0,0,1,0,
				0,1,1,1,1,0
			],[	// x s w
				0,0,0,0,0,0,
				0,1,0,0,0,0,
				0,1,0,0,0,0,
				0,1,0,0,0,0
			],[	// x w
				0,0,0,0,0,0,
				0,1,0,0,0,0,
				0,0,0,0,0,0,
				0,1,0,0,0,0
			],[	// w 2
				0,1,0,0,0,0,
				0,1,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// s 2
				0,1,0,0,0,0,
				0,0,0,0,0,0,
				0,1,0,0,0,0,
				0,0,0,0,0,0
			],[	// 2
				0,1,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 2 6
				0,1,0,0,0,1,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 2 6 y
				0,1,0,0,0,1,
				0,0,0,0,0,1,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 6 y h
				0,0,0,0,0,1,
				0,0,0,0,0,1,
				0,0,0,0,0,1,
				0,0,0,0,0,0
			],[	// y h n
				0,0,0,0,0,0,
				0,0,0,0,0,1,
				0,0,0,0,0,1,
				0,0,0,0,0,1
			],[	// h n
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,1,
				0,0,0,0,0,1
			],[	// n
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,1
			],[	// n z
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				1,0,0,0,0,1
			],[	// n z a
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				1,0,0,0,0,0,
				1,0,0,0,0,1
			],[	// z a
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				1,0,0,0,0,0,
				1,0,0,0,0,0
			],[	// z a q
				0,0,0,0,0,0,
				1,0,0,0,0,0,
				1,0,0,0,0,0,
				1,0,0,0,0,0
			],[	// a q 1
				1,0,0,0,0,0,
				1,0,0,0,0,0,
				1,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 1 3
				1,0,1,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			],[	// 1 3 4 h
				1,0,1,1,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,1,
				0,0,0,0,0,0
			],[	// 1 3 4 h a s q
				1,0,1,1,0,0,
				1,0,0,0,0,0,
				1,1,0,0,0,1,
				0,0,0,0,0,0
			]
		];
	}
	
	*synthNames
	{
		^[
			\DeathByChocobo,\BinaryBlackHole2,\FriedOwlBites,\UnicronEaterOfPlanets,\PiplupIsBirdType,\WasabiGolem,
			\DemonCurry,\StoneBehemoth,\noise1,\Psychonauts,\DigitalSunrise,\Protoplasm,
			\BinaryBlackHole,\FauxPho,\LiquidXenakis,\ToneCloud2,\noise2,\N64Rx,
			\noise4,\noise5,\noise6,\noise3,\MetalPercussion2,\Coalescence2
		];
	}
	
	*synthPanning
	{
		^[
			Array.series(24, -1, 2/24),
			Array.series(24, -1, 2/24),
			Array.series(24, -1, 2/24)
		];
	}
	
	*setSyncArg
	{|parent, oscAddr, objName, argIndex, argValue, group, subGroup|
		
		if(subGroup.asString == "s", {
				MindFlayer.userStates.at(objName.asString).states[argIndex] = argValue;
				
				MindFlayer.buttonStates = Array.fill(MindFlayer.keyNames.size, {0.0});
				
				MindFlayer.userStates.do{|user|
					MindFlayer.buttonStates = (MindFlayer.buttonStates + (user.states / MindFlayer.userStates.size)).clip(0.0,1.0);
				};
				
				parent.updateButtonStates;
				
				MindFlayer.buttonStates.do{|val,i|
					if(val > 0.0,{
						if(MindFlayer.synths[i].isNil,{
							MindFlayer.synths[i] = Synth(
								MindFlayerPartI.synthNames[i],
								[
									"timbreval",val,
									"amp",MindFlayerServerItems.currentVolume,
									"panX", MindFlayerPartI.synthPanning[0][i],
									"panY", MindFlayerPartI.synthPanning[1][i],
									"panZ", MindFlayerPartI.synthPanning[2][i]
								],
								MindFlayerServerItems.synthGroup
							);
						},{
							MindFlayer.synths[i].set("timbreval",val);
						});
					});
					
					if(val <= 0.0,{
						if(MindFlayer.synths[i].notNil,{
							MindFlayer.synths[i].release;
							MindFlayer.synths[i] = nil;
						});
					});
				};
			});
	}
	
	*synthDefWrapper
	{
		|name,function|
		switch(Manticore.speakerConfiguration,
			\stereo, {
				(
				SynthDef(name,{|out=0, panX=0, panY=0, panZ=0|
					var sig;
					
					sig = SynthDef.wrap(function);
					
					sig = LeakDC.ar(sig);
					
					Out.ar(out,Pan2.ar(sig,panX));
				}).store;
				);
			},
			\quad, {
				(
				SynthDef(name,{|out=0, panX=0, panY=0, panZ=0, amp=0.5, gate=1, timberVal=0|
					var sig;
					
					sig = SynthDef.wrap(function, nil, [timberVal,gate,amp]);
					
					sig = LeakDC.ar(sig);
					
					Out.ar(out,Pan4.ar(sig,panX,panY,amp));
				}).store;
				);
			},
			\cube, {
				(
				SynthDef(name,{|out=0, panX=0, panY=0, panZ=0, amp=0.5, gate=1, timberVal=0|
					var sig;
					
					sig = SynthDef.wrap(function, nil, [timberVal,gate,amp]);
					
					sig = LeakDC.ar(sig);
					
					Out.ar(out,CubePan.ar(sig,panX,panY,panZ,amp));
				}).store;
				);
			}
		);
	}
	
	*storeSynthDefs
	{
		// TODO: fix "e", "q"
		(
		SynthDef("lagmonster",{ arg out = 0, freq = 440, amp = 0.1, num = 1, gate = 1;
		var sig, env;
			env = EnvGen.kr(Env.asr(0.01, 1, 3, 'sine'), gate, doneAction:2);
			
			sig = Decay2.ar(Impulse.ar(num), 0.01, 0.5);
			
			sig = sig * LPF.ar(Pulse.ar(freq, SinOsc.kr(LFNoise1.kr(2, 10, 17), 0, 0.5, 0.5)),freq*2);
			
			Out.ar(out, Pan2.ar(sig, 0, amp*env));
		}).store;
		);
		
		MindFlayerPartI.synthDefWrapper(\DeathByChocobo,{
			|amp=1.0,timbreval=0.0,gate=1|
			var pulse,signal,formlet,pulse2,env,mod;
			mod = Lag.kr((timbreval+0.0001)*40,1);
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			pulse = Pulse.ar(mod.linexp(0.0,40.0,1.0,20.0),0.5,0.5,0.5);
			pulse = Pulse.ar(mod.linexp(0.0,40.0,40.0,3000.0)*pulse,0.5,0.1);
			pulse2 = Pulse.ar(mod.linexp(0.0,40.0,1.0,20.0),0.5,1);
			pulse = Pulse.ar(mod.linexp(0.0,40.0,40.0,3000.0)*pulse2,0.5,0.1)+pulse;
			formlet = Formlet.ar(pulse,mod.linlin(0.0,40.0,5000.0,20.0),0.0,0.001,10).clip2(0.1);
			signal = (pulse+formlet).softclip*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\FauxPho,{
			|amp=0.2,timbreval=0,gate=1|
			var pulse,signal,formlet,dust,env,env2,pulse2,verb,filter,mod;
			mod = Lag.kr((timbreval+0.0001)*40,1);
			dust = Dust.ar(mod.linlin(0.0,40.0,80.0,2.0));
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			env2 = EnvGen.ar(Env.asr(0.0001,1.0,mod.linlin(0.0,40.0,2.0,20.0)),gate:Trig.kr(dust),doneAction:0);
			pulse = LFPulse.ar(5,0,0.5) * Pulse.ar(40.0,0.5,1);
			pulse2 = LFPulse.ar(10,0,0.5) * Pulse.ar(80.0,0.5,1);
			filter = RLPF.ar(pulse+pulse2,Lag.kr(mod.linlin(0.0,40.0,1000,160.0),0.1),0.03);
			verb = FreeVerb.ar(filter,mod.linlin(0.0,40.0,0.2,1.0),0.0,0.0)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\FriedOwlBites,{
			|amp=0.25,timbreval=0,gate=1|
			var sine,pulse,pulse2,signal,formlet,dust,env,delay,delayIn,feed,mod;
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			mod = Lag.kr((timbreval+0.0001)*40,1);
			mod = Lag.kr(mod,0.1);
			pulse = LFPulse.ar(mod.linexp(0.0,40.0,1.0,15.0),0,0.5);
			pulse2 = LFPulse.ar(mod.linexp(0.0,40.0,1.0,15.0),0,0.5);
			pulse = Pulse.ar(20.0,0.5,pulse ring2: pulse2);
			sine = SinOsc.ar(mod.linlin(0.0,40.0,200.0,10000.0) ring2: pulse,0,0.25);
			feed = LocalIn.ar(1);
			delayIn = (sine ring4: pulse) ring2: feed;
			delay = BufDelayC.ar(LocalBuf(44100),delayIn,mod.linlin(0.0,40.0,1.0,0.0001),0.5,delayIn);
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			LocalOut.ar(delay*0.1);
			signal = delay*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\UnicronEaterOfPlanets,{
			|amp=0.125,timbreval=0,gate=1|
			var pulse,signal,formlet,dust,env,trig,env2,sine,filter,verb,mod;
			mod = Lag.kr((timbreval+0.0001)*40,1);
			trig = Trig.kr(HPZ2.kr(mod));
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			env2 = EnvGen.ar(Env.asr(0.0001,1.0,mod.linexp(0.0,40.0,1.0,4.0),-16),gate:trig,doneAction:0)+0.1;
			env2 = env2*LFNoise0.ar(mod.linlin(0.0,40.0,0.3,5.0),0.5,0.5);
			pulse = Pulse.ar(mod.linexp(0.0,40.0,10.0,20.0),0.5,0.5,0.5);
			sine = SinOsc.ar(mod.linexp(0.0,40.0,10.0,5.0)*env2,0,0.5,0.5);
			sine = LFPulse.ar(mod.linlin(0.0,40.0,20,5.5)*sine,0,0.5);
			sine = LFPulse.ar(mod.linlin(0.0,40.0,1000.0,40.0) * sine * (1-env2).abs,0,0.5);
			sine = LeakDC.ar((sine*1000*env2));
			filter = RHPF.ar(sine,(mod.linexp(0.0,40.0,50.0,5000.0)*env2),0.1).clip2(1.0);
			filter = RLPF.ar(filter,(mod.linexp(0.0,40.0,5000.0,1000.0)*env2.abs),0.1).clip2(1.0)+filter;
			filter = BLowShelf.ar(filter,80,0.3,3);
			verb = FreeVerb.ar(filter,0.25,1.0,1.0)+(filter*0.5)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\PiplupIsBirdType,{
			|amp=1.0,timbreval=0,gate=1|
			var feed,signal,formlet,delay,env,trig,env2,sine,sine2,pitch,mod;
			mod = Lag.kr((timbreval+0.0001)*40,1);
			feed = LocalIn.ar(1);
			trig = Trig.kr(HPZ2.kr(mod));
			pitch = Lag.kr(Pitch.kr(feed),0.1);
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			env2 = EnvGen.ar(Env.asr(0.0001,1.0,2,-4),gate:trig,doneAction:0);
			sine = Pulse.ar(pitch[1]*200,0.5);
			sine = sine+SinOsc.ar(Lag.ar(ZeroCrossing.ar(sine),0.01),0.5,1.75);
			sine2 = Pulse.ar((env2*ZeroCrossing.ar(feed)*mod.linlin(0.0,40.0,0.25,0.0125)).max(mod.linlin(0.0,40.0,10.0,5.0)),0.5);
			sine2 = sine2+SinOsc.ar(pitch[1]*sine2*10.25,0,0.5);
			sine2 = sine2+SinOsc.ar(mod.linexp(0.0,40.0,1.0,50.0) *sine2 * sine);
			sine = sine + sine2;
			sine = (sine*0.1) + feed;
			delay = BufCombC.ar(LocalBuf(44100),sine,mod.linlin(0.0,40.0,9000.reciprocal,5.reciprocal),pitch[1],0.5,sine);
			delay = BufCombC.ar(LocalBuf(44100*2),delay,mod.linexp(0.0,40.0,10000.reciprocal,5.reciprocal),pitch[1]*2,0.5,delay);
			signal = BLowShelf.ar(sine,160,0.5,12);
			LocalOut.ar(delay*0.4);
			signal = signal*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\WasabiGolem,{
			|amp=1.0,timbreval=0,gate=1|
			var pulse,signal,formlet,dust,env,trig,env2,freq,width,sine,noise,noise2,zero,feed,mod;
			var delay,controlFeed,control;
			mod = Lag.kr((timbreval+0.0001)*40,1);
			feed = LocalIn.ar(1);
			controlFeed = LocalIn.kr(1);
			trig = Impulse.ar(mod.linexp(0.0,40.0,10.0,40.0));
			env = EnvGen.ar(Env.asr(0.5,1.0,1.0),gate:gate,doneAction:2);
			env2 = EnvGen.ar(Env.asr(0.0001,1.0,0.5),gate:trig,doneAction:0);
			control = controlFeed;
			sine = SinOsc.ar(mod.linexp(0.0,40.0,1.0,20.0),0,0.5,0.5);
			noise = LFNoise0.ar(mod.linlin(0.0,40.0,10.0,1.0)).linexp(-1.0,1.0,20.0,2000.0);
			noise2 = LFNoise1.ar(mod.linlin(0.0,40.0,2.0,10.0),0.4,0.4);
			zero = ((Pitch.kr(feed)[0])).wrap2(mod.linlin(0.0,40.0,500.0,2000.0));
			freq = Demand.ar(PulseDivider.ar(trig,mod.linlin(0.0,40.0,2.0,1.0)),0,Dshuf([zero,zero,control,control,control],inf));
			width = Demand.ar(Impulse.ar(mod.linlin(0.0,40.0,1.0,13.0)),0,Dseq([noise2],inf));
			pulse = Pulse.ar(freq,width,0.2*env2*env)+(feed*mod.linlin(0.0,40.0,0.1,0.5));
			pulse = pulse + Pulse.ar((freq*0.5),noise,0.1*env2*env);
			pulse = BLowShelf.ar(pulse,160,0.3,3);
			delay = BufDelayC.ar(LocalBuf(44100),pulse,mod.linlin(0.0,40.0,1.0,0.0001).round(0.025),1,pulse);
			delay = BufDelayC.ar(LocalBuf(44100*2),delay,mod.linlin(0.0,40.0,2.0,1.025).round(0.025),1,delay);
			LocalOut.ar(delay*0.4);
			LocalOut.kr(freq*mod.linlin(0.0,40.0,1.4,1.45));
			signal = pulse*env+delay;
			signal = LeakDC.ar(signal.softclip);
		});
		
		MindFlayerPartI.synthDefWrapper(\DemonCurry,{
			|amp=0.7,timbreval=0,gate=1|
			var pulse,signal,formlet,dust,env,trig,env2,verb,filter,noise,filtFreq,sine,env3,trig2,mod;
			Lag.kr(mod = (timbreval+0.0001)*40,1);
			trig = Impulse.ar(mod.linlin(0.0,40.0,5.0,120.0));
			trig2 = Trig.ar(trig);
			env = EnvGen.ar(Env.asr(0.5,1.0,5.0),gate:gate,doneAction:2);
			env2 = EnvGen.ar(Env.asr(0.0,1.0,0.0125,-16),gate:trig,doneAction:0);
			env3 = EnvGen.ar(Env.asr(0.01,1.0,0.25,-8),gate:trig2,doneAction:0);
			noise = LFNoise1.ar(mod.linlin(0.0,40.0,0.5,5.0),0.5,0.5).linlin(0.0,1.0,20.0,2000.0);
			noise = Demand.ar(trig,0,noise);
			filtFreq = env2*mod.linexp(0.0,40.0,2000.0,16000.0);
			noise = WhiteNoise.ar(0.35*env2);
			filter = BMoog.ar(env2*2,filtFreq,0.4,2,0);
			verb = FreeVerb.ar(filter*env2,0.9,0.85,0.0);
			sine = SinOsc.ar(40.0,0,env3*0.25);
			signal = verb;
			signal = LeakDC.ar(signal)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\StoneBehemoth,{
			|freq=110,timbreval=0,amp, gate|
			var signal,env,osc,spring,constant = 5,damping = 0.001,impulse,time,feed,num;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(0.01, 1, 3, 'sine'), gate, doneAction:2);
			time = num.linlin(0,1,0.5,16.0).round(0.25);
			
			constant = LFNoise0.ar(time).linlin(-1,1,1,15);
			damping = LFNoise0.ar(time).linlin(-1,1,0.0000001,0.001);
			
			impulse = Decay2.ar(Impulse.ar(time), 0.01, 2.0);
			spring = Spring.ar(impulse,constant, damping);
			spring = (spring * num.linlin(0,1,4,12)); 
							
			osc = SinOsc.ar(0,spring.fold2(8pi), 1.0) * impulse*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\Psychonauts,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,filter,mod,num;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(1.5, 1, 3, 'sine'), gate, doneAction:2);				num = Slew.kr(num,0.05);
			
			mod = SinOsc.ar(num.linlin(0,1,1/16,1/2)).linlin(-1,1,num.linlin(0,1,0.1,8),num.linlin(0,1,1,16));
			mod = SinOsc.ar(mod,0,0.5)+0.5;
			
			osc = Gendy4.ar(2,3,minfreq:20, maxfreq:100, durscale:0.0, initCPs:160);
			osc = (FreeVerb.ar(osc,1.0,0.99,0.01)*mod) + osc;
			filter = RLPF.ar(osc,num.linlin(0,1,250,2000,2),0.3, 1.0)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\N64Rx,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,spring,constant = 5,damping = 0.001,impulse,time,feed,num;
			var mod, mod2;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(0.01, 1, 3, 'sine'), gate, doneAction:2);
			time = num.linlin(0,1,0.5,32.0).round(0.25);
			impulse = Decay2.ar(Impulse.ar(time), 0.01, 2.0);
			feed = LocalIn.ar(4);
			mod = [
				LFNoise0.ar(time).linlin(-1,1,0.1,1,32),
				LFNoise0.ar(time).linlin(-1,1,0.1,1,32),
				LFNoise0.ar(time).linlin(-1,1,0.1,1,32),
				LFNoise0.ar(time).linlin(-1,1,0.1,1,32)
			];
			mod = [
				SinOsc.ar(mod[0]+(feed*num*15),0.0,num.linlin(0,1,0,12)).round(1.0) + 1,
				SinOsc.ar(mod[1]+(feed*num*15),0.25pi,num.linlin(0,1,0,8)).round(1.0) + 1,
				SinOsc.ar(mod[2]+(feed*num*15),0.5pi,num.linlin(0,1,0,16)).round(1.0) + 1,
				SinOsc.ar(mod[3]+(feed*num*15),0.75pi,num.linlin(0,1,0,17)).round(1.0) + 1
			];	
			
			osc = [
				LFPulse.ar((freq+(mod[0]*(num*15))).abs,0,0.5,0.5).trunc(0.5**2) * impulse,
				LFPulse.ar((freq*mod[1]).abs,0,0.5,0.5).trunc(0.5**2) * impulse,
				LFPulse.ar((freq+(mod[2]*(num*15))).abs,0,0.5,0.5).trunc(0.5**2) * impulse,
				LFPulse.ar((freq*mod[3]).abs,0,0.5,0.5).trunc(0.5**2) * impulse
			];
			osc = Mix.ar(osc)*0.75;
			LocalOut.ar(osc);
			
			osc*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\DigitalSunrise,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,impulse,time,feed,mod,num;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(0.01, 1, 3, 'sine'), gate, doneAction:2);
			num = Slew.kr(num,0.05);
			time = num.linlin(0,1,0.5,16.0).round(0.25);
			impulse = Decay2.ar(Impulse.ar(time), 0.01, 2.0);
							
			mod = [
				SinOsc.ar(num.linlin(0,1,0.1,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.125,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.175,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.2,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.225,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.251,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.275,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.3,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.325,1.0),0,440,440),
				SinOsc.ar(num.linlin(0,1,0.35,1.0),0,440,440) 
			];
			osc = [
				Formant.ar(110,mod[0]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[1]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[2]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[3]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[4]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[5]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[6]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44)),
				Formant.ar(110,mod[7]*num.linlin(0,1,0.125,2),num.linlin(0,1,10,44))
			];
			osc = (osc*num.linlin(0,1,10,100)).fold2(mod);
			osc = Mix.ar(osc)*0.1;
			osc = FreeVerb.ar(osc,0.5,0.9,0.2)*0.333*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\Protoplasm,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,impulse,time,feed,num;
			var freqFilter,phase;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(0.01, 1, 5, 'sine'), gate, doneAction:2);
			time = num.linlin(0,1,0.125,1.5);
			impulse = Decay2.ar(Impulse.ar(time), 0.01, num.linlin(0,1,4,4));
			num = Slew.kr(num,0.1);
			
			freq = Formlet.kr(
				Impulse.kr(num.linlin(0,1,10,30) ! 2), 
				A2K.kr(num.linlin(0,1,100,30)),
				0.00001, 
				A2K.kr(num.linlin(0,1,1.25,2.25))
			);
			phase = Formlet.kr(
				Dust.kr(num.linlin(0,1,1,12) ! 2), 
				A2K.kr(num.linlin(0,1,100,30)),
				0.0005, 
				A2K.kr(num.linlin(0,1,1.25,2.25))
			)*num.linlin(0,1,1,60);
				
			osc = SinOsc.ar(freq*200+[500,600] - 100,phase.fold2(8pi),1.0) * impulse;
			osc = (osc * num.linlin(0,1,0.5,12)).softclip(1) * num.linlin(0,1,1,0.5)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\BinaryBlackHole,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,impulse,time,feed,num;
			var ddParam,adParam;
			num = Lag.kr(timbreval+0.0001,1);
			env = EnvGen.kr(Env.asr(0.01, 1, 5, 'sine'), gate, doneAction:2);
			time = num.linlin(0,1,0.125,1.5);
			impulse = Decay2.ar(Impulse.ar(time), 0.01, num.linlin(0,1,4,4));
			num = Slew.kr(num,0.25);
			
			adParam = SinOsc.ar(LFNoise2.ar(num.linlin(0,1,10,240),num.linlin(0,1,80,660),0.6),0,0.9,0.1);
			ddParam = SinOsc.ar(LFNoise2.ar(num.linlin(0,1,10,240),num.linlin(0,1,80,660),0.6),0,0.9,0.1);
			osc = Gendy4.ar(6,6,adParam,ddParam,num.linlin(0,1,10,2100),mul:8.0)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\BinaryBlackHole2,{
			|freq = 110,timbreval = 0,amp = 0.05, gate = 1|
			var signal,env,osc,impulse,time,feed,num;
			var ddParam,adParam,buffer;
			num = Lag.kr(timbreval+0.0001,1);
			buffer = [
				LocalBuf(SampleRate.ir*0.5).clear,
				LocalBuf(SampleRate.ir*0.5).clear
			];

			env = EnvGen.kr(Env.asr(0.01, 1, 5, 'sine'), gate, doneAction:2);
			num = Slew.kr(num,1);
			num = num +0.2;
			
			adParam = SinOsc.ar(LFNoise2.ar(num.linlin(0,1,12,12),num.linlin(0,1,8,120),0.6),0,0.9,0.1);
			ddParam = SinOsc.ar(LFNoise2.ar(num.linlin(0,1,12,12),num.linlin(0,1,8,120),0.6),0.5,0.9,0.1);
			
			adParam = BufCombN.ar(buffer,adParam,num.linlin(0,1,0.00001,0.0001),0.3);
			ddParam = BufCombN.ar(buffer,ddParam,num.linlin(0,1,0.00001,0.0001),-0.25);
			osc = Gendy3.ar(6,6,adParam,ddParam,num.linlin(0,1,100,1000),initCPs:24,knum: num.linlin(0,1,1,24),mul:2.0)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\LiquidXenakis,{
			|freq = 110,timbreval = 0,amp = 0.1, gate = 1|
			var signal,env,osc,impulse,time,feed,num;
			var ddParam,adParam,buffer;
			num = Lag.kr(timbreval+0.0001,1);
			buffer = [
				LocalBuf(SampleRate.ir*0.5).clear,
				LocalBuf(SampleRate.ir*0.5).clear
			];

			env = EnvGen.kr(Env.asr(0.01, 1, 5, 'sine'), gate, doneAction:2);
			time = num.linlin(0,1,0.25,3);
			impulse = Decay2.ar(Impulse.ar(time), 0.01, num.linlin(0,1,10,10));
			num = Slew.kr(num,1);
			
			adParam = Pulse.ar(LFNoise2.ar(num.linlin(0,1,12,12),num.linlin(0,1,80,120),0.6),0.5,0.9,0.1)*impulse;
			ddParam = Pulse.ar(LFNoise2.ar(num.linlin(0,1,12,12),num.linlin(0,1,80,120),0.6),0.5,0.9,0.1)*impulse;
			
			adParam = BufCombC.ar(buffer,adParam,num.linlin(0,1,0.00001,0.00005),0.3);
			ddParam = BufCombC.ar(buffer,ddParam,num.linlin(0,1,0.00001,0.00005),-0.3);
			osc = Gendy4.ar(6,6,adParam,ddParam,num.linlin(0,1,90,200),initCPs:24,knum: 2,mul:2.0);
			
			osc = SinOsc.ar(num.linlin(0,1,1,1000.01),osc*num.linlin(0,1,5,100).fold2(8pi),1.0);
			osc = FreeVerb.ar(osc,0.25,0.85,0.15)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise1, {
			arg amp = 0.5, freq = 60, timbreval = 1, gate = 1, pan = 0.0, dur = 20, delayTime =0.00001;
			var env, buf, source, delay, signal, filter,density;
			density = (timbreval+0.0001)*0.25;
			// for never ending fun!
			env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			
			buf = LocalBuf(44100, 1);
			density = 4*density;
			source =  SinOsc.ar(HenonC.ar(freq/density, LFNoise2.kr(freq/density, Impulse.ar(density)), SinOsc.kr(LFNoise2.ar(freq/density, freq, freq + density), density, 0.5))*100 + 50)*0.6;
			
			delay = amp*BufDelayC.ar(buf, source, delayTime);
			
			signal = Limiter.ar(delay, 0.9, 0.01);
			filter = LPF.ar(signal, 2400/density)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise2, {
			arg amp = 0.5, freq = 200, timbreval = 1, gate = 1, dur = 20, delayTime =0.00001;
			var env, buf, source, noise, delay, signal, filter,density;
			density = (timbreval+0.0001)*0.1;
				env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			//for never ending fun!		
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			//density = 0.1*density;
			buf = LocalBuf(44100, 1);
			source = SinOsc.ar(density, 0, 0.5);
			noise =  VarSaw.ar(GbmanL.ar(Pitch.kr(source)[0]/density)*(120))*0.2;
			delay = amp*BufDelayC.ar(buf, noise, delayTime);
			signal = Limiter.ar(delay, 0.7, 0.01);
			filter = LPF.ar(signal, 1200)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise3, {
			arg amp = 0.1, timbreval = 1, gate = 1, dur = 3, delayTime =0.00001;
			var env, buf, source, delay, signal, filter,density;
			density = timbreval+0.0001;
			// for never ending fun!
			env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			buf = LocalBuf(44100, 1);
			source = amp*DynKlank.ar(
					`[[100 + density, 200 + density,400 + density, 800 + density],
						nil,
						[density/10,density/20,density/40,density/80]],PinkNoise.ar(5*density));
			
			delay = amp*BufDelayC.ar(buf, source, delayTime);	
			signal = Limiter.ar(delay, 0.7, 0.01);
			filter = LPF.ar(signal, 1200)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise4, {
			arg amp = 0.5, timbreval = 1, gate = 1, dur = 3, delayTime =0.01;
			var env, buf, source, freq, noise, delay, signal, filter,density;
			density = (timbreval+0.0001)*30;
			// for never ending fun!
			env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			//density = 30*density;
			buf = LocalBuf(44100, 1);
			source = amp*VarSaw.ar(LFNoise0.kr([8/density, 2/density, 4/density]),4/density);
			freq = Pitch.kr(source)[0];
			noise =  DynKlank.ar(`[freq, nil, density/(1+density)], Impulse.ar(0.25*density));
			 delay = amp*BufDelayC.ar(buf, noise, delayTime);	
			signal = Limiter.ar(delay, 0.7, 0.01);
			filter = LPF.ar(signal, 1200)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise5, {
			arg amp = 0.5, freq = 20, timbreval = 1, gate = 1, dur = 3, delayTime =0.01;
			var env, buf, source, noise, delay, signal, filter,density;
			density = (timbreval+0.0001)*10;
			// for never ending fun!
			env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			//density = 10*density;
			buf = LocalBuf(44100, 1);
			source = amp*CombN.ar(Decay.ar(SinOsc.ar(freq/density, 0, 0.5), 0.2, PinkNoise.ar),3, 3/density, 10/density);
			freq = Pitch.kr(source)[0];
			noise =  DynKlank.ar(`[freq, nil, 0.004*density], Dust.ar(density));
			 delay = amp*BufDelayC.ar(buf, noise, delayTime);	
			signal = Limiter.ar(delay, 0.7, 0.01);
			filter = LPF.ar(signal, 1200)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\noise6, {
			arg amp = 0.5, timbreval = 1, gate = 1, dur = 3, delayTime =0.01;
			var env, buf, source, freq, noise1, noise2, all, delay, signal, filter,density;
			density = timbreval+0.0001;
			// for never ending fun!
			env = EnvGen.ar(Env.asr(1.0, 1.0, dur,-4),gate,doneAction:2);
			//env = EnvGen.ar(Env.sine( dur, 1.0), gate,doneAction:2);
			buf = LocalBuf(44100, 1);
			source = SinOsc.ar(100*density, 0, 0.5);
			freq = Pitch.kr(source)[0];
			freq = freq/density;
			noise1 = FBSineC.ar(
						LFNoise2.kr(freq, 1e4, 1e4)/density, 
						LFNoise2.kr(freq, 32, 33), 
						LFNoise2.kr(freq, 0.5),
						LFNoise2.kr(freq, 0.05, 1.05),
						LFNoise2.kr(freq, 0.3, 0.3)) * 0.2;
			noise2 = PitchShift.ar(noise1, 0.02, SinOsc.kr(0.15*density,0, 0.5), 0, 0.00001);
			all =   noise1 + noise2;
			 delay = amp*BufDelayC.ar(buf, all, delayTime);	
			signal = Limiter.ar(delay, 0.7, 0.01);
			filter = LPF.ar(signal, 1200)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\ToneCloud2,{
			| center = 700, centLag = 0.5, timbreval = 1, deviationHz = 10 devHzLag = 5, devLag = 8, amp = 0.3 ampLag = 0.5, gate = 1, pan = 0, panLag = 5, dur= 10 |
			var sig, env,deviation;
			deviation = Lag.kr((timbreval+0.0001)*center,1);
			env = EnvGen.kr(Env.asr(1,amp/3,1,'sine'),gate,doneAction:2);
			sig = Mix.new(
				Saw.ar(
				LFNoise2.ar(Lag.kr(deviationHz,devHzLag).dup(30), Lag.kr(deviation,devLag).dup(30),  Lag.kr(center,centLag)),
				env*Lag.kr(amp/20,ampLag)
				)
			);
			
			sig = LPF.ar(sig, Lag.kr(LFNoise2.kr(2,deviation,center*13),centLag));
			
			sig = LPF.ar(
				AllpassC.ar(
					Ringz.ar(
						sig,
						{exprand(100, 2500)}.dup(20)
						,{exprand(0.2, 3)}.dup(20)).mean,0.01,0.01,4,1.3),
				1000);
			sig = HPF.ar(sig,800)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\MetalPercussion2,{
			arg timbreval=1,freq=200, amp=0.4, gate=1, type=0, pan=0, dur = 5;
			var sig, env, driver,den;
			den = Lag.kr(timbreval*12+0.0001,1);
			env = EnvGen.kr(Env.asr(0,amp,2,'sine'),gate,doneAction:2);
			sig = CombC.ar(
				HPF.ar(
					PinkNoise.ar(
						Decay2.ar(
							Impulse.ar(den*gate,0,LFNoise1.kr(300))
							,0.05,0.2)
						)
					,LFNoise1.kr(10).range(200,5000))
				,0.01,1/(
						SinOsc.kr(40).range(freq,freq*1.5)+LFNoise1.kr(1,freq/4).round(10)
					)
				,3)*env;
		});
		
		MindFlayerPartI.synthDefWrapper(\Coalescence2,{
			arg amp = 0.2, timbreval = 1, gate=1;
			var mod, sig, val, env;
			env = EnvGen.kr(Env.asr(1, amp, 2, 'sine'), gate,doneAction:2);
			val = Lag.kr((timbreval+0.0001)*300,1);
			mod = SinOsc.kr(
				539
				,0
				,0.03125
				,0.0625);
			
			sig = PitchShift.ar(
			DelayN.ar(
				SinOsc.ar(
				val
					
					,0
					,0.5)
				,1
				,LFSaw.kr(
					300
					,0
					,mod
					,mod)
				,1)
			,0.02,0.6,0,SinOsc.kr(
				0.05
				,pi
				,0.0005
				,0.00025)
			).madd(
				amp
				);
					
			sig = Pan2.ar(
				AllpassC.ar(
					Ringz.ar(
						sig,
						{exprand(100, 20000)}.dup(60)
						,{exprand(1, 4)}.dup(60)).mean,0.01,0.01,4,1.3)
				,LFNoise1.kr(0.125));
			
			LPF.ar(sig, 2000)*env;
		});
	}
}

MindFlayerPartII
{
	*scoreText
	{
		^[
			"r (play in waves throughout)"
		];
	}
	
	*buttonStates
	{
		^[
			// LAGMonster
			[	// r
				0,0,0,0,0,0,
				0,0,0,1,0,0,
				0,0,0,0,0,0,
				0,0,0,0,0,0
			]
		];
	}
	
	*synthNames
	{
		^Array.fill(24, {"MindFlayerTest"});
	}
	
	*setSyncArg
	{|parent, oscAddr, objName, argIndex, argValue, group, subGroup|
		
		if(subGroup.asString == "s", {
				MindFlayer.userStates.at(objName.asString).states[argIndex] = argValue;
				
				MindFlayer.buttonStates = Array.fill(MindFlayer.keyNames.size, {0.0});
				
				MindFlayer.userStates.do{|user|
					MindFlayer.buttonStates = (MindFlayer.buttonStates + (user.states / MindFlayer.userStates.size)).clip(0.0,1.0);
				};
				
				parent.updateButtonStates;
				
				MindFlayer.buttonStates.do{|val,i|
					if(val > 0.0,{
						if(MindFlayer.synths[i].isNil,{
							MindFlayer.synths[i] = Synth(MindFlayerPartII.synthNames[i],["timberval",val],MindFlayerServerItems.synthGroup);
						},{
							MindFlayer.synths[i].set("timberval",val);
						})
					});
					
					if(val <= 0.0,{
						if(MindFlayer.synths[i].notNil,{
							MindFlayer.synths[i].release;
							MindFlayer.synths[i] = nil;
						});
					});
				};
			});
	}
	
	*storeSynthDefs
	{
		(
		SynthDef("MindFlayerTest",{|out=0,timberval=0,gate=1|
			var sig, env;
			
			env = EnvGen.kr(Env.asr(0.01, 1, 3, 'sine'), gate, doneAction:2);
			
			sig = SinOsc.ar(440 * Lag.kr(timberval.linlin(0.0,1.0,1.0,16.0),0.1),0,1);
			
			Out.ar(out,sig*env);
		}).store;
		);
	}
}
